﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Threading.Tasks;

namespace Microsoft.Live
{
	public static class ConnectClientExtensions
	{
		public static Task<LiveOperationCompletedEventArgs> CopyAsyncTask (this LiveConnectClient connectClient, string path, string destination, object userstate = null)
		{
			var tcs = new TaskCompletionSource<LiveOperationCompletedEventArgs> ();

			try {
				connectClient.CopyCompleted += (s, e) =>
				{
					if (e.Cancelled) {
						tcs.TrySetCanceled ();
					} else if (e.Error == null) {
						tcs.TrySetResult (e);
					} else {
						tcs.TrySetException (e.Error);
					}
				};

				if (userstate != null) {
					connectClient.CopyAsync (path, destination, userstate);
				} else {
					connectClient.CopyAsync (path, destination);
				}
			} catch (Exception ex) {
				tcs.TrySetException (ex);
			}

			return tcs.Task;
		}

		public static Task<LiveOperationCompletedEventArgs> DeleteAsyncTask (this LiveConnectClient connectClient, string path, object userstate = null)
		{
			var tcs = new TaskCompletionSource<LiveOperationCompletedEventArgs> ();

			try {
				connectClient.DeleteCompleted += (s, e) =>
				{
					if (e.Cancelled) {
						tcs.TrySetCanceled ();
					} else if (e.Error == null) {
						tcs.TrySetResult (e);
					} else {
						tcs.TrySetException (e.Error);
					}
				};

				if (userstate != null) {
					connectClient.DeleteAsync (path, userstate);
				} else {
					connectClient.DeleteAsync (path);
				}
			} catch (Exception ex) {
				tcs.TrySetException (ex);
			}

			return tcs.Task;
		}

		public static Task<LiveDownloadCompletedEventArgs> DownloadAsyncTask (this LiveConnectClient connectClient, string path, object userstate = null)
		{
			var tcs = new TaskCompletionSource<LiveDownloadCompletedEventArgs> ();

			try {
				connectClient.DownloadCompleted += (s, e) =>
				{
					if (e.Cancelled) {
						tcs.TrySetCanceled ();
					} else if (e.Error == null) {
						tcs.TrySetResult (e);
					} else {
						tcs.TrySetException (e.Error);
					}
				};

				if (userstate != null) {
					connectClient.DownloadAsync (path, userstate);
				} else {
					connectClient.DownloadAsync (path);
				}
			} catch (Exception ex) {
				tcs.TrySetException (ex);
			}

			return tcs.Task;
		}

		public static Task<LiveOperationCompletedEventArgs> GetAsyncTask (this LiveConnectClient connectClient, string path, object userstate = null)
		{
			var tcs = new TaskCompletionSource<LiveOperationCompletedEventArgs> ();

			try {
				connectClient.GetCompleted += (s, e) =>
										{
											if (e.Cancelled) {
												tcs.TrySetCanceled ();
											} else if (e.Error == null) {
												tcs.TrySetResult (e);
											} else {
												tcs.TrySetException (e.Error);
											}
										};

				if (userstate != null) {
					connectClient.GetAsync (path, userstate);
				} else {
					connectClient.GetAsync (path);
				}
			} catch (Exception ex) {
				tcs.TrySetException (ex);
			}

			if (tcs.Task.Exception != null) {
				throw tcs.Task.Exception;
			}

			return tcs.Task;
		}

		public static Task<LiveOperationCompletedEventArgs> MoveAsyncTask (this LiveConnectClient connectClient, string path, string destination, object userstate = null)
		{
			var tcs = new TaskCompletionSource<LiveOperationCompletedEventArgs> ();

			try {
				connectClient.MoveCompleted += (s, e) =>
				{
					if (e.Cancelled) {
						tcs.TrySetCanceled ();
					} else if (e.Error == null) {
						tcs.TrySetResult (e);
					} else {
						tcs.TrySetException (e.Error);
					}
				};

				if (userstate != null) {
					connectClient.MoveAsync (path, destination, userstate);
				} else {
					connectClient.MoveAsync (path, destination);
				}
			} catch (Exception ex) {
				tcs.TrySetException (ex);
			}

			return tcs.Task;
		}

		public static Task<LiveOperationCompletedEventArgs> PostAsyncTask (this LiveConnectClient connectClient, string path, string body, object userstate = null)
		{
			var tcs = new TaskCompletionSource<LiveOperationCompletedEventArgs> ();

			try {
				connectClient.PostCompleted += (s, e) =>
				{
					if (e.Cancelled) {
						tcs.TrySetCanceled ();
					} else if (e.Error == null) {
						tcs.TrySetResult (e);
					} else {
						tcs.TrySetException (e.Error);
					}
				};

				if (userstate != null) {
					connectClient.PostAsync (path, body, userstate);
				} else {
					connectClient.PostAsync (path, body);
				}
			} catch (Exception ex) {
				tcs.TrySetException (ex);
			}

			return tcs.Task;
		}
		public static Task<LiveOperationCompletedEventArgs> PostAsyncTask (this LiveConnectClient connectClient, string path, IDictionary<string, object> body, object userstate = null)
		{
			var tcs = new TaskCompletionSource<LiveOperationCompletedEventArgs> ();

			try {
				connectClient.PostCompleted += (s, e) =>
				{
					if (e.Cancelled) {
						tcs.TrySetCanceled ();
					} else if (e.Error == null) {
						tcs.TrySetResult (e);
					} else {
						tcs.TrySetException (e.Error);
					}
				};

				if (userstate != null) {
					connectClient.PostAsync (path, body, userstate);
				} else {
					connectClient.PostAsync (path, body);
				}
			} catch (Exception ex) {
				tcs.TrySetException (ex);
			}

			return tcs.Task;
		}

		public static Task<LiveOperationCompletedEventArgs> PutAsyncTask (this LiveConnectClient connectClient, string path, string body, object userstate = null)
		{
			var tcs = new TaskCompletionSource<LiveOperationCompletedEventArgs> ();

			try {
				connectClient.PutCompleted += (s, e) =>
				{
					if (e.Cancelled) {
						tcs.TrySetCanceled ();
					} else if (e.Error == null) {
						tcs.TrySetResult (e);
					} else {
						tcs.TrySetException (e.Error);
					}
				};

				if (userstate != null) {
					connectClient.PutAsync (path, body, userstate);
				} else {
					connectClient.PutAsync (path, body);
				}
			} catch (Exception ex) {
				tcs.TrySetException (ex);
			}

			return tcs.Task;
		}
		public static Task<LiveOperationCompletedEventArgs> PutAsyncTask (this LiveConnectClient connectClient, string path, IDictionary<string, object> body, object userstate = null)
		{
			var tcs = new TaskCompletionSource<LiveOperationCompletedEventArgs> ();

			try {
				connectClient.PutCompleted += (s, e) =>
				{
					if (e.Cancelled) {
						tcs.TrySetCanceled ();
					} else if (e.Error == null) {
						tcs.TrySetResult (e);
					} else {
						tcs.TrySetException (e.Error);
					}
				};

				if (userstate != null) {
					connectClient.PutAsync (path, body, userstate);
				} else {
					connectClient.PutAsync (path, body);
				}
			} catch (Exception ex) {
				tcs.TrySetException (ex);
			}

			return tcs.Task;
		}

		public static Task<LiveOperationCompletedEventArgs> UploadAsyncTask (this LiveConnectClient connectClient, string path, string filename,
			Stream inputStream, OverwriteOption overwriteOption = OverwriteOption.Overwrite, object userstate = null)
		{
			var tcs = new TaskCompletionSource<LiveOperationCompletedEventArgs>();

			try
			{
				connectClient.UploadCompleted += (s, e) =>
				{
					if (e.Cancelled)
					{
						tcs.TrySetCanceled();
					}
					else if (e.Error == null)
					{
						tcs.TrySetResult(e);
					}
					else
					{
						tcs.TrySetException(e.Error);
					}
				};

				connectClient.UploadAsync(path, filename, inputStream, OverwriteOption.DoNotOverwrite, userstate);
			}
			catch (Exception ex)
			{
				tcs.TrySetException(ex);
			}

			return tcs.Task;
		}
	}
}
